#include <EEPROM.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ESP8266WiFi.h>
#include "config.h"
#include "myFunctions.h"
#include "web.h"
//所有存储体的定义
WiFiConfig wifiConfig;  // 这就是定义！
WebConfig webConfig;
UserConfig userConfig;
WiFiClient wifiClient; // 声明一个WiFiClient对象
BearSSL::WiFiClientSecure client;
//测试网络联通
void ICACHE_FLASH_ATTR testNetworkConnection() {
  Serial.println("🔍 测试网络连通性...");

  // 测试DNS解析
  IPAddress serverIP;
  if (!WiFi.hostByName("api.gzqizhen.com", serverIP)) {
    Serial.println("❌ DNS解析失败");
    return;
  }
  Serial.print("✅ DNS解析成功: ");
  Serial.println(serverIP);

  // 测试TCP连接
  WiFiClient testClient;
  if (!testClient.connect("api.gzqizhen.com", 443)) {
    Serial.println("❌ TCP连接失败");
    return;
  }
  Serial.println("✅ TCP连接成功");
  testClient.stop();
}

bool ICACHE_FLASH_ATTR saveWebConfig() {
  EEPROM.put(WEB_CONFIG_ADDR, webConfig);
  bool success = EEPROM.commit();
  if (success) {
    Serial.println("配置保存成功");
    printWebConfig();
  } else {
    Serial.println("配置保存失败");
  }

  return success;
}
StaticJsonDocument<200> RequestSendKey(String body, String url) {
  // 方法1: 使用WiFiClientSecure（推荐）
  BearSSL::WiFiClientSecure client;
  client.setInsecure(); // 忽略证书验证
  HTTPClient http;
  //
  http.begin(client, url);
  http.addHeader("Content-Type", "application/json");
  http.addHeader("User-Agent", "ESP8266");
  // 添加更详细的请求体
  String requestBody = body;
  Serial.print("请求体: ");
  Serial.println(requestBody);
  Serial.print("请求链接: ");
  Serial.println(url);
  int httpCode = http.POST(requestBody);
  Serial.print("📥 HTTP状态码: ");
  Serial.println(httpCode);
  StaticJsonDocument<200> doc;
  if (httpCode > 0) {
    String response = http.getString();
    Serial.print("📨 服务器响应: ");
    Serial.println(response);
    if (httpCode == 200) {
      // 处理成功响应
      DeserializationError error = deserializeJson(doc, response);
      // 提取data.url字段
      if (!error && doc.containsKey("data")) {
        return doc;
      } else {
        Serial.println("❌ JSON解析失败或缺少url字段");
        doc.clear();
      }
    } else {
      Serial.print("❌ 服务器返回错误: ");
      Serial.println(httpCode);
      doc.clear();
    }
  } else {
    Serial.print("❌ HTTP请求失败: ");
    Serial.println(httpCode);
    Serial.print("错误信息: ");
    Serial.println(http.errorToString(httpCode));
    testNetworkConnection();
    doc.clear();
  }
  http.end();
  return doc;
}
//如果type=1，则为首次请求
void ICACHE_FLASH_ATTR presskey(int keydat, int type) {
  //会员卡号长度大于5
  if (strlen(userConfig.snid) > 0) {
    JsonDocument response = RequestSendKey(createRequestBody(keydat, userConfig.snid, type), "https://api.gzqizhen.com/api/esp/getkey");
    if (response.containsKey("data")) {
      const int score = response["data"]["sc"];//剩余积分
      const int cc = response["data"]["cc"];//币数
      const int tc = response["data"]["tc"];//票数
      const int xc = response["data"]["xc"];//扣币消费数
      const int pc = response["data"]["pc"];//累计积分

      userConfig.scroe = score;
      userConfig.cc = cc;
      userConfig.tc = tc;
      userConfig.xc = xc;
      userConfig.pc = pc;
      setUserConfig();
      if (response.containsKey("data") && response["data"]["status"] > 0 && response["data"]["click"] > 0) {
        const int pulseCount = response["data"]["click"];//票数
        int fq = 100;
        if (response["data"]["fq"] > 0) {
          fq = response["data"]["fq"];
        }

        output_pulse(pulseCount, fq);//
        //脉冲宽度：50ms（适合大多数投币器）
        //脉冲间隔：100ms（避免信号粘连）
        Serial.print("上分: ");
        Serial.println(pulseCount);
      }
      Serial.print("剩余积分: ");
      Serial.println(score);
      Serial.print("币数: ");
      Serial.println(cc);
      Serial.print("票数: ");
      Serial.println(tc);
      Serial.print("扣币消费数: ");
      Serial.println(xc);
      Serial.print("累计积分: ");
      Serial.println(pc);

      int code = response["code"];
      Serial.print("响应代码: ");
      Serial.println(code);
    }
  } else {
    Serial.print("请插卡: ");
    Serial.println(userConfig.snid);
  }
}
//在用户插卡的时候获取用户数据
bool setUserConfig() {
  // 方法1：清零结构体
  // memset(&config, 0, sizeof(config));  // 所有数据设为0
  // 保存到EEPROM
  EEPROM.put(USER_CONFIG_ADDR, userConfig);
  bool success =  EEPROM.commit();
  Serial.println("配置用户数据");
  return success;
}
//在用户拔卡的时候清除用户数据
void clearUserConfig() {
  // 方法1：清零结构体
  memset(&userConfig, 0, sizeof(userConfig));  // 所有数据设为0
  // 保存到EEPROM
  EEPROM.put(USER_CONFIG_ADDR, userConfig);
  EEPROM.commit();
  Serial.println("用户配置已清除");
}
//首次启动发送自己的wifi数据，或者从数据库获取配置信息
void requestAndSaveIP() {
  // 方法1: 使用WiFiClientSecure（推荐）
  BearSSL::WiFiClientSecure client;
  client.setInsecure(); // 忽略证书验证
  HTTPClient http;
  http.begin(client, "https://api.gzqizhen.com/api/esp/espbell");
  // 或者方法2: 使用普通的WiFiClient（如果服务器支持HTTP）
  // HTTPClient http;
  // http.begin(wifiClient, "http://api.gzqizhen.com/api/esp/espbell");
  http.addHeader("Content-Type", "application/json");
  http.addHeader("User-Agent", "ESP8266");
  // 添加更详细的请求体
  String requestBody = createRequestBody(0, "init", 0); // 或者根据API文档添加必要字段
  Serial.print("📤 发送请求体: ");
  Serial.println(requestBody);
  int httpCode = http.POST(requestBody);
  Serial.print("📥 HTTP状态码: ");
  Serial.println(httpCode);
  if (httpCode > 0) {
    String response = http.getString();
    Serial.print("📨 服务器响应: ");
    Serial.println(response);
    if (httpCode == 200) {
      // 处理成功响应
      StaticJsonDocument<200> doc;
      DeserializationError error = deserializeJson(doc, response);
      // 提取data.url字段
      if (!error && doc.containsKey("data") && doc["data"].containsKey("url")) {
        const char* url = doc["data"]["url"];
        const char* timex = doc["time"];
        const int k1 = doc["data"]["k1"];
        const int k2 = doc["data"]["k2"];
        const int k3 = doc["data"]["k3"];
        // 保存url
        strncpy(webConfig.url, url, sizeof(webConfig.url) - 1);
        webConfig.url[sizeof(webConfig.url) - 1] = '\0'; // 确保字符串终止
        // 保存time
        strncpy(webConfig.time, timex, sizeof(webConfig.time) - 1);
        webConfig.time[sizeof(webConfig.time) - 1] = '\0'; // 确保字符串终止
        webConfig.k1 = k1;
        webConfig.k2 = k2;
        webConfig.k3 = k3;
        webConfig.configured = true;
        // 保存到EEPROM
        bool savesuccess = saveWebConfig();
        if (savesuccess) {
          Serial.print("配置获取成功！");
        }
        //如果服务器返回wifi账号密码，本地存储为空，则保存服务器的数据
        if (doc["data"].containsKey("ssid") && doc["data"].containsKey("pwd") && !wifiConfig.ssid) {
          const char* ssid = doc["data"]["ssid"];
          const char* pwd = doc["data"]["pwd"];
          // 保存配置到EEPROM
          strncpy(wifiConfig.ssid, ssid, sizeof(wifiConfig.ssid) - 1);
          strncpy(wifiConfig.password, pwd, sizeof(wifiConfig.password) - 1);
          wifiConfig.configured = true;
          saveWiFiConfig();
        }
        Serial.print("地址偏移: ");
        Serial.println(WEB_CONFIG_ADDR);
      } else {
        Serial.println("❌ JSON解析失败或缺少ip字段");
      }
    } else {
      Serial.print("❌ 服务器返回错误: ");
      Serial.println(httpCode);
    }
  } else {
    Serial.print("❌ HTTP请求失败: ");
    Serial.println(httpCode);
    Serial.print("错误信息: ");
    Serial.println(http.errorToString(httpCode));
  }

  http.end();
}
void ICACHE_FLASH_ATTR printwifiConfig() {
  Serial.println("=== wifi配置 ===");
  Serial.print("账号: "); Serial.println(wifiConfig.ssid);
  Serial.print("密码: "); Serial.println(wifiConfig.password);
  Serial.print("已配置: "); Serial.println(wifiConfig.configured ? "是" : "否");
  Serial.println("===============");
}
void ICACHE_FLASH_ATTR printWebConfig() {
  Serial.println("=== Web配置 ===");
  Serial.print("url: "); Serial.println(webConfig.url);
  Serial.print("time: "); Serial.println(webConfig.time);
  Serial.print("K1: "); Serial.println(webConfig.k1);
  Serial.print("K2: "); Serial.println(webConfig.k2);
  Serial.print("K3: "); Serial.println(webConfig.k3);
  Serial.print("已配置: "); Serial.println(webConfig.configured ? "是" : "否");
  Serial.println("===============");
}
void ICACHE_FLASH_ATTR printUserConfig() {
  Serial.println("=== 会员卡数据 ===");
  Serial.print("snid: "); Serial.println(userConfig.snid);
  Serial.print("剩余积分: "); Serial.println(userConfig.scroe);
  Serial.print("币数: "); Serial.println(userConfig.cc);
  Serial.print("票数: "); Serial.println(userConfig.tc);
  Serial.print("消费数: "); Serial.println(userConfig.xc);
  Serial.print("剩余积分: "); Serial.println(userConfig.pc);

  Serial.println("===============");
}
void printDeviceInfo() {
  Serial.println("=== 设备信息 ===");
  Serial.printf("芯片ID: 0x%08X\n", ESP.getChipId());
  Serial.printf("MAC地址: %s\n", WiFi.macAddress().c_str());
  Serial.printf("Flash ID: 0x%08X\n", ESP.getFlashChipId());
  Serial.printf("Flash大小: %d MB\n", ESP.getFlashChipSize() / 1024 / 1024);
  Serial.printf("CPU频率: %d MHz\n", ESP.getCpuFreqMHz());
  Serial.printf("SDK版本: %s\n", ESP.getSdkVersion());
  Serial.println("========================");
}
//脉冲型号输出
void ICACHE_FLASH_ATTR output_pulse(int count, int frequency) {
  unsigned long lastYieldTime = millis();
  unsigned long startTime = millis();
  if (count <= 0 || frequency <= 0) return;
  int period = 1000000 / frequency; // 周期(微秒)
  int halfPeriod = period / 2;

  pinMode(COIN_PIN, OUTPUT);
  digitalWrite(COIN_PIN, LOW); // 初始化为低电平

  for (int i = 0; i < count; i++) {
    digitalWrite(COIN_PIN, HIGH);
    delayMicroseconds(halfPeriod);
    digitalWrite(COIN_PIN, LOW);
    delayMicroseconds(halfPeriod);
    // 每50ms喂一次狗（更频繁）
    if (millis() - lastYieldTime > 50) {
      yield();
      lastYieldTime = millis();
    }
  }
  unsigned long actualTime = millis() - startTime;
  Serial.printf("✅ 脉冲输出完成，实际耗时: %lums\n", actualTime);
}
String ICACHE_FLASH_ATTR createRequestBody(int keyValue, String sn, int type) {
  StaticJsonDocument<200> doc;
  //首次请求

  if (keyValue) {
    doc["key"] = keyValue;
    doc["sn"] = sn;
  } else {
    if (type) {
      doc["key"] = keyValue;
      doc["sn"] = sn;
      doc["type"] = type;
    } else {
      doc["ssid"] = wifiConfig.ssid;
      doc["pwd"] = wifiConfig.password;
    }
  }

  doc["fid"] = ESP.getFlashChipId();
  doc["cid"] = ESP.getChipId();
  String jsonString;
  serializeJson(doc, jsonString);
  return jsonString;
}
void printStoredIP() {

  Serial.println("存储偏移:");
  Serial.println(SYS_CONFIG_ADDR);
  //printWebConfig();
}
